Pelajari cara mengkategorikan dan menangani kesalahan secara efektif dalam React Error Boundaries, meningkatkan stabilitas aplikasi dan pengalaman pengguna.
Kategorisasi Kesalahan React Error Boundary: Panduan Komprehensif
Penanganan kesalahan adalah aspek penting dalam membangun aplikasi React yang kuat dan mudah dipelihara. Sementara React Error Boundaries menyediakan mekanisme untuk menangani kesalahan yang terjadi selama rendering dengan baik, memahami cara mengkategorikan dan menanggapi berbagai jenis kesalahan sangat penting untuk menciptakan aplikasi yang benar-benar tangguh. Panduan ini mengeksplorasi berbagai pendekatan untuk kategorisasi kesalahan dalam Error Boundaries, menawarkan contoh praktis dan wawasan yang dapat ditindaklanjuti untuk meningkatkan strategi manajemen kesalahan Anda.
Apa itu React Error Boundaries?
Diperkenalkan di React 16, Error Boundaries adalah komponen React yang menangkap kesalahan JavaScript di mana saja di pohon komponen anak mereka, mencatat kesalahan tersebut, dan menampilkan UI fallback alih-alih membuat seluruh pohon komponen crash. Mereka berfungsi mirip dengan blok try...catch, tetapi untuk komponen.
Karakteristik utama Error Boundaries:
- Penanganan Kesalahan Tingkat Komponen: Mengisolasi kesalahan dalam subtree komponen tertentu.
- Degradasi Halus: Mencegah seluruh aplikasi crash karena kesalahan komponen tunggal.
- UI Fallback Terkendali: Menampilkan pesan yang ramah pengguna atau konten alternatif saat terjadi kesalahan.
- Pencatatan Kesalahan: Memfasilitasi pelacakan dan debugging kesalahan dengan mencatat informasi kesalahan.
Mengapa Mengkategorikan Kesalahan di Error Boundaries?
Hanya menangkap kesalahan saja tidak cukup. Penanganan kesalahan yang efektif membutuhkan pemahaman apa yang salah dan menanggapi sesuai dengan itu. Mengkategorikan kesalahan dalam Error Boundaries menawarkan beberapa manfaat:- Penanganan Kesalahan Bertarget: Jenis kesalahan yang berbeda mungkin memerlukan respons yang berbeda. Misalnya, kesalahan jaringan mungkin memerlukan mekanisme coba lagi, sementara kesalahan validasi data mungkin memerlukan koreksi input pengguna.
- Peningkatan Pengalaman Pengguna: Menampilkan pesan kesalahan yang lebih informatif berdasarkan jenis kesalahan. Pesan generik "Terjadi kesalahan" kurang membantu daripada pesan spesifik yang menunjukkan masalah jaringan atau input yang tidak valid.
- Debugging yang Ditingkatkan: Mengkategorikan kesalahan memberikan konteks yang berharga untuk debugging dan mengidentifikasi akar penyebab masalah.
- Pemantauan Proaktif: Melacak frekuensi berbagai jenis kesalahan untuk mengidentifikasi masalah yang berulang dan memprioritaskan perbaikan.
- UI Fallback Strategis: Menampilkan UI fallback yang berbeda tergantung pada kesalahan, memberikan informasi atau tindakan yang lebih relevan kepada pengguna.
Pendekatan untuk Kategorisasi Kesalahan
Beberapa teknik dapat digunakan untuk mengkategorikan kesalahan dalam React Error Boundaries:
1. Menggunakan instanceof
Operator instanceof memeriksa apakah suatu objek adalah instance dari kelas tertentu. Ini berguna untuk mengkategorikan kesalahan berdasarkan jenis kesalahan bawaan atau khusus mereka.
Contoh:
class NetworkError extends Error {
constructor(message) {
super(message);
this.name = "NetworkError";
}
}
class ValidationError extends Error {
constructor(message) {
super(message);
this.name = "ValidationError";
}
}
class MyErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false, error: null, errorInfo: null };
}
static getDerivedStateFromError(error) {
// Update state so the next render will show the fallback UI.
return { hasError: true, error: error };
}
componentDidCatch(error, errorInfo) {
// You can also log the error to an error reporting service
console.error("Caught error:", error, errorInfo);
this.setState({errorInfo: errorInfo});
}
render() {
if (this.state.hasError) {
// You can render any custom fallback UI
let errorMessage = "Terjadi kesalahan.";
if (this.state.error instanceof NetworkError) {
errorMessage = "Terjadi kesalahan jaringan. Harap periksa koneksi Anda dan coba lagi.";
} else if (this.state.error instanceof ValidationError) {
errorMessage = "Terjadi kesalahan validasi. Harap tinjau input Anda.";
}
return (
<div>
<h2>Kesalahan!</h2>
<p>{errorMessage}</p>
<details style={{ whiteSpace: 'pre-wrap' }}>
{this.state.error && this.state.error.toString()}<br />
{this.state.errorInfo.componentStack}
</details>
</div>
);
}
return this.props.children;
}
}
Penjelasan:
- Kelas
NetworkErrordanValidationErrorkhusus didefinisikan, memperluas kelasErrorbawaan. - Dalam metode
renderdari komponenMyErrorBoundary, operatorinstanceofdigunakan untuk memeriksa jenis kesalahan yang tertangkap. - Berdasarkan jenis kesalahan, pesan kesalahan spesifik ditampilkan di UI fallback.
2. Menggunakan Kode atau Properti Kesalahan
Pendekatan lain adalah menyertakan kode atau properti kesalahan dalam objek kesalahan itu sendiri. Ini memungkinkan kategorisasi yang lebih terperinci berdasarkan skenario kesalahan spesifik.
Contoh:
function fetchData(url) {
return new Promise((resolve, reject) => {
fetch(url)
.then(response => {
if (!response.ok) {
const error = new Error("Permintaan jaringan gagal");
error.code = response.status; // Tambahkan kode kesalahan khusus
reject(error);
}
return response.json();
})
.then(data => resolve(data))
.catch(error => reject(error));
});
}
class MyErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false, error: null, errorInfo: null };
}
static getDerivedStateFromError(error) {
// Update state so the next render will show the fallback UI.
return { hasError: true, error: error };
}
componentDidCatch(error, errorInfo) {
// You can also log the error to an error reporting service
console.error("Caught error:", error, errorInfo);
this.setState({errorInfo: errorInfo});
}
render() {
if (this.state.hasError) {
let errorMessage = "Terjadi kesalahan.";
if (this.state.error.code === 404) {
errorMessage = "Sumber daya tidak ditemukan.";
} else if (this.state.error.code >= 500) {
errorMessage = "Kesalahan server. Harap coba lagi nanti.";
}
return (
<div>
<h2>Kesalahan!</h2>
<p>{errorMessage}</p>
<details style={{ whiteSpace: 'pre-wrap' }}>
{this.state.error && this.state.error.toString()}<br />
{this.state.errorInfo.componentStack}
</details>
</div>
);
}
return this.props.children;
}
}
Penjelasan:
- Fungsi
fetchDatamenambahkan properticodeke objek kesalahan, yang mewakili kode status HTTP. - Komponen
MyErrorBoundarymemeriksa properticodeuntuk menentukan skenario kesalahan spesifik. - Pesan kesalahan yang berbeda ditampilkan berdasarkan kode kesalahan.
3. Menggunakan Pemetaan Kesalahan Terpusat
Untuk aplikasi yang kompleks, memelihara pemetaan kesalahan terpusat dapat meningkatkan organisasi dan pemeliharaan kode. Ini melibatkan pembuatan kamus atau objek yang memetakan jenis atau kode kesalahan ke pesan kesalahan dan logika penanganan tertentu.
Contoh:
const errorMap = {
"NETWORK_ERROR": {
message: "Terjadi kesalahan jaringan. Harap periksa koneksi Anda.",
retry: true,
},
"INVALID_INPUT": {
message: "Input tidak valid. Harap tinjau data Anda.",
retry: false,
},
404: {
message: "Sumber daya tidak ditemukan.",
retry: false,
},
500: {
message: "Kesalahan server. Harap coba lagi nanti.",
retry: true,
},
"DEFAULT": {
message: "Terjadi kesalahan.",
retry: false,
},
};
function handleCustomError(errorType) {
const errorDetails = errorMap[errorType] || errorMap["DEFAULT"];
return errorDetails;
}
class MyErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false, errorDetails: null, errorInfo: null };
}
static getDerivedStateFromError(error) {
// Update state so the next render will show the fallback UI.
const errorDetails = handleCustomError(error.message);
return { hasError: true, errorDetails: errorDetails };
}
componentDidCatch(error, errorInfo) {
// You can also log the error to an error reporting service
console.error("Caught error:", error, errorInfo);
this.setState({errorInfo: errorInfo});
}
render() {
if (this.state.hasError) {
const { message } = this.state.errorDetails;
return (
<div>
<h2>Kesalahan!</h2>
<p>{message}</p>
<details style={{ whiteSpace: 'pre-wrap' }}>
{this.state.errorDetails.message}<br />
{this.state.errorInfo.componentStack}
</details>
</div>
);
}
return this.props.children;
}
}
function MyComponent(){
const [data, setData] = React.useState(null);
React.useEffect(() => {
try {
throw new Error("NETWORK_ERROR");
} catch (e) {
throw e;
}
}, []);
return <div></div>;
}
Penjelasan:
- Objek
errorMapmenyimpan informasi kesalahan, termasuk pesan dan flag coba lagi, berdasarkan jenis atau kode kesalahan. - Fungsi
handleCustomErrormengambil detail kesalahan darierrorMapberdasarkan pesan kesalahan dan mengembalikan default jika tidak ada kode spesifik yang ditemukan. - Komponen
MyErrorBoundarymenggunakanhandleCustomErroruntuk mendapatkan pesan kesalahan yang sesuai darierrorMap.
Praktik Terbaik untuk Kategorisasi Kesalahan
- Definisikan Jenis Kesalahan yang Jelas: Tetapkan serangkaian jenis atau kode kesalahan yang konsisten untuk aplikasi Anda.
- Berikan Informasi Kontekstual: Sertakan detail yang relevan dalam objek kesalahan untuk memfasilitasi debugging.
- Pusatkan Logika Penanganan Kesalahan: Gunakan pemetaan kesalahan terpusat atau fungsi utilitas untuk mengelola penanganan kesalahan secara konsisten.
- Catat Kesalahan Secara Efektif: Berintegrasi dengan layanan pelaporan kesalahan untuk melacak dan menganalisis kesalahan dalam produksi. Layanan populer termasuk Sentry, Rollbar, dan Bugsnag.
- Uji Penanganan Kesalahan: Tulis unit test untuk memverifikasi bahwa Error Boundaries Anda menangani berbagai jenis kesalahan dengan benar.
- Pertimbangkan Pengalaman Pengguna: Tampilkan pesan kesalahan yang informatif dan ramah pengguna yang memandu pengguna menuju resolusi. Hindari jargon teknis.
- Pantau Tingkat Kesalahan: Lacak frekuensi berbagai jenis kesalahan untuk mengidentifikasi masalah yang berulang dan memprioritaskan perbaikan.
- Internasionalisasi (i18n): Saat menyajikan pesan kesalahan kepada pengguna, pastikan bahwa pesan Anda diinternasionalkan dengan benar untuk mendukung berbagai bahasa dan budaya. Gunakan pustaka seperti
i18nextatau React Context API untuk mengelola terjemahan. - Aksesibilitas (a11y): Pastikan pesan kesalahan Anda dapat diakses oleh pengguna dengan disabilitas. Gunakan atribut ARIA untuk memberikan konteks tambahan ke pembaca layar.
- Keamanan: Berhati-hatilah tentang informasi apa yang Anda tampilkan dalam pesan kesalahan, terutama di lingkungan produksi. Hindari mengekspos data sensitif yang dapat dieksploitasi oleh penyerang. Misalnya, jangan menampilkan raw stack traces ke pengguna akhir.
Contoh Skenario: Menangani Kesalahan API dalam Aplikasi E-commerce
Pertimbangkan aplikasi e-commerce yang mengambil informasi produk dari API. Skenario kesalahan potensial meliputi:
- Kesalahan Jaringan: Server API tidak tersedia atau koneksi internet pengguna terputus.
- Kesalahan Otentikasi: Token otentikasi pengguna tidak valid atau kedaluwarsa.
- Kesalahan Sumber Daya Tidak Ditemukan: Produk yang diminta tidak ada.
- Kesalahan Server: Server API mengalami kesalahan internal.
Menggunakan Error Boundaries dan kategorisasi kesalahan, aplikasi dapat menangani skenario ini dengan baik:
// Contoh (Sederhana)
async function fetchProduct(productId) {
try {
const response = await fetch(`/api/products/${productId}`);
if (!response.ok) {
if (response.status === 404) {
throw new Error("PRODUCT_NOT_FOUND");
} else if (response.status === 401 || response.status === 403) {
throw new Error("AUTHENTICATION_ERROR");
} else {
throw new Error("SERVER_ERROR");
}
}
return await response.json();
} catch (error) {
if (error instanceof TypeError && error.message === "Failed to fetch") {
throw new Error("NETWORK_ERROR");
}
throw error;
}
}
class ProductErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false, errorDetails: null, errorInfo: null };
}
static getDerivedStateFromError(error) {
const errorDetails = handleCustomError(error.message); // Gunakan errorMap seperti yang ditunjukkan sebelumnya
return { hasError: true, errorDetails: errorDetails };
}
componentDidCatch(error, errorInfo) {
console.error("Caught error:", error, errorInfo);
this.setState({errorInfo: errorInfo});
}
render() {
if (this.state.hasError) {
const { message, retry } = this.state.errorDetails;
return (
<div>
<h2>Kesalahan!</h2>
<p>{message}</p>
{retry && <button onClick={() => window.location.reload()}>Coba Lagi</button>}
</div>
);
}
return this.props.children;
}
}
Penjelasan:
- Fungsi
fetchProductmemeriksa kode status respons API dan melemparkan jenis kesalahan spesifik berdasarkan status. - Komponen
ProductErrorBoundarymenangkap kesalahan ini dan menampilkan pesan kesalahan yang sesuai. - Untuk kesalahan jaringan dan kesalahan server, tombol "Coba Lagi" ditampilkan, memungkinkan pengguna untuk mencoba permintaan lagi.
- Untuk kesalahan otentikasi, pengguna mungkin dialihkan ke halaman login.
- Untuk kesalahan sumber daya tidak ditemukan, pesan yang menunjukkan bahwa produk tidak ada ditampilkan.
Kesimpulan
Mengkategorikan kesalahan dalam React Error Boundaries sangat penting untuk membangun aplikasi yang tangguh dan ramah pengguna. Dengan menggunakan teknik seperti pemeriksaaninstanceof, kode kesalahan, dan pemetaan kesalahan terpusat, Anda dapat menangani berbagai skenario kesalahan secara efektif dan memberikan pengalaman pengguna yang lebih baik. Ingatlah untuk mengikuti praktik terbaik untuk penanganan kesalahan, pencatatan, dan pengujian untuk memastikan bahwa aplikasi Anda menangani situasi yang tidak terduga dengan baik.
Dengan menerapkan strategi ini, Anda dapat secara signifikan meningkatkan stabilitas dan kemampuan pemeliharaan aplikasi React Anda, memberikan pengalaman yang lebih lancar dan lebih andal bagi pengguna Anda, terlepas dari lokasi atau latar belakang mereka.
Sumber Daya Lebih Lanjut: